/****************************************************************************
 * Copyright (C) 2011
 * by Dimok
 *
 * This software is provided 'as-is', without any express or implied
 * warranty. In no event will the authors be held liable for any
 * damages arising from the use of this software.
 *
 * Permission is granted to anyone to use this software for any
 * purpose, including commercial applications, and to alter it and
 * redistribute it freely, subject to the following restrictions:
 *
 * 1. The origin of this software must not be misrepresented; you
 * must not claim that you wrote the original software. If you use
 * this software in a product, an acknowledgment in the product
 * documentation would be appreciated but is not required.
 *
 * 2. Altered source versions must be plainly marked as such, and
 * must not be misrepresented as being the original software.
 *
 * 3. This notice may not be removed or altered from any source
 * distribution.
 ***************************************************************************/
#include "ThemeLoader.h"
#include "ThemeInfosWindow.h"
#include "../CTheme.h"
#include "../../Prompts/PromptWindows.h"
#include "../../FileOperations/DirList.h"
#include "../../FileOperations/fileops.h"
#include "../../Controls/Application.h"

ThemeLoader::ThemeLoader()
	: FlyingButtonsMenu()
{
	buttonImgData = Resources::GetImageData("theme_box.png");
	
	for(int i = 0; i < 4; ++i)
		ThemePreviews[i] = NULL;
	
	SetupMainButtons();
}

ThemeLoader::~ThemeLoader()
{
	Resources::Remove(buttonImgData);
	
	for(int i = 0; i < 4; ++i)
	{
		if(ThemePreviews[i])
			delete ThemePreviews[i];
	}
}

void ThemeLoader::SetupMainButtons()
{
	ThemeList.clear();

	DirList ThemeDir(Settings.ThemePath, ".them", DirList::Files);
	if (!ThemeDir.GetFilecount())
		ShowError(tr( "No themes found." ));

	for(int i = 0; i < ThemeDir.GetFilecount(); ++i)
	{
		u8 *buffer = NULL;
		u32 filesize;
		
		LoadFileToMem(ThemeDir.GetFilepath(i), &buffer, &filesize);
		
		if(!buffer)
			continue;
		
		buffer[filesize-1] = '\0';
		
		int size = ThemeList.size();
		ThemeList.resize(size+1);
		
		ThemeList[size].Filepath = ThemeDir.GetFilepath(i);
		GetNodeText(buffer, "Theme-Title:", ThemeList[size].Title);
		GetNodeText(buffer, "Theme-Team:", ThemeList[size].Team);
		GetNodeText(buffer, "Theme-Version:", ThemeList[size].Version);
		GetNodeText(buffer, "Image-Folder:", ThemeList[size].ImageFolder);
		
		if(ThemeList[size].Title.empty() && ThemeDir.GetFilename(i))
		{
			ThemeList[size].Title = ThemeDir.GetFilename(i);
			size_t pos = ThemeList[size].Title.rfind('.');
			if(pos != std::string::npos)
				ThemeList[size].Title.erase(pos);
		}
		
		if(ThemeList[size].ImageFolder.empty())
		{
			ThemeList[size].ImageFolder = ThemeDir.GetFilepath(i);
			size_t pos = ThemeList[size].ImageFolder.rfind('.');
			if(pos != std::string::npos)
				ThemeList[size].ImageFolder.erase(pos);
			ThemeList[size].ImageFolder += '/';
		}
		else
		{
			std::string tempString = ThemeList[size].ImageFolder;
			ThemeList[size].ImageFolder = Settings.ThemePath;
			ThemeList[size].ImageFolder += '/';
			ThemeList[size].ImageFolder += tempString;
			ThemeList[size].ImageFolder += '/';
		}
		
		ThemeLoader::SetMainButton(size, ThemeList[size].Title.c_str(), buttonImgData, NULL);
		free(buffer);
	}
	
	SetPageIndicators();
}

void ThemeLoader::SetMainButton(int position, const char * ButtonText, GuiImageData * imageData, GuiImageData * themeImg)
{
	if(position < (int) mainButton.size())
	{
		delete mainButtonImg[position];
		delete mainButtonImgOver[position];
		delete mainButtonTxt[position];
		delete mainButton[position];
	}
	else
	{
		mainButtonImg.resize(position+1);
		mainButtonImgOver.resize(position+1);
		mainButtonTxt.resize(position+1);
		mainButton.resize(position+1);
	}

	mainButtonImg[position] = new GuiImage(imageData);
	mainButtonImgOver[position] = new GuiImage(themeImg);
	mainButtonImgOver[position]->SetScale(0.4);
	mainButtonImgOver[position]->SetAlignment(ALIGN_CENTER | ALIGN_TOP);
	mainButtonImgOver[position]->SetPosition(0, -45);
	
	mainButtonTxt[position] = new GuiText(ButtonText, thInt("18 - theme_menu mainbutton theme_title text size"), thColor("r=0 g=0 b=0 a=255 - theme_menu mainbutton theme_title text color"));
	mainButtonTxt[position]->SetAlignment(ALIGN_CENTER | ALIGN_TOP);
	mainButtonTxt[position]->SetPosition(0, 10);
	mainButtonTxt[position]->SetMaxWidth(imageData->GetWidth() - 10, DOTTED);

	mainButton[position] = new GuiButton(imageData->GetWidth(), imageData->GetHeight());
	mainButton[position]->SetAlignment(ALIGN_LEFT | ALIGN_TOP);
	mainButton[position]->SetImage(mainButtonImg[position]);
	mainButton[position]->SetImageOver(mainButtonImg[position]);
	mainButton[position]->SetSoundOver(btnSoundOver);
	mainButton[position]->SetSoundClick(btnSoundClick);
	mainButton[position]->SetIcon(mainButtonImgOver[position]);
	mainButton[position]->SetLabel(mainButtonTxt[position]);
	mainButton[position]->SetTrigger(trigA);
	mainButton[position]->SetEffectGrow();
	mainButton[position]->Clicked.connect(this, &ThemeLoader::OnMainButtonClick);
	mainButton[position]->StateChanged.connect(this, &ThemeLoader::OnStateChange);
	
	switch(position % 4)
	{
		case 0:
			mainButton[position]->SetPosition(90, 75);
			break;
		case 1:
			mainButton[position]->SetPosition(340, 75);
			break;
		case 2:
			mainButton[position]->SetPosition(90, 230);
			break;
		case 3:
			mainButton[position]->SetPosition(340, 230);
			break;
		default:
			break;
	}
}

GuiImageData * ThemeLoader::GetImageData(int theme)
{
	char filepath[300];
	snprintf(filepath, sizeof(filepath), "%stheme_preview.png", ThemeList[theme].ImageFolder.c_str());

	return (new GuiImageData(filepath));
}

bool ThemeLoader::GetNodeText(const u8 *buffer, const char *node, std::string &outtext)
{
	const char * nodeText = strcasestr((const char *) buffer, node);
	if(!nodeText)
		return false;

	nodeText += strlen(node);

	while(*nodeText == ' ') nodeText++;

	while(*nodeText != '\0' && *nodeText != '\\' && *nodeText != '\n' && *nodeText != '"')
	{
		outtext.push_back(*nodeText);
		nodeText++;
	}

	return true;
}

void ThemeLoader::AddMainButtons()
{
	for(u32 i = 0; i < mainButton.size(); ++i)
		Remove(mainButton[i]);
	
	int firstItem = currentPage*4;
	
	int n = 0;
	for(int i = firstItem; i < (int) mainButton.size() && i < firstItem+4; ++i)
	{
		if(ThemePreviews[n])
			delete ThemePreviews[n];
		ThemePreviews[n] = GetImageData(i);
		mainButtonImgOver[i]->SetImage(ThemePreviews[n]);
		Append(mainButton[i]);
		n++;
	}
	
	AddPageIndicators();
}

void ThemeLoader::OnStateChange(GuiElement *sender, int state, int stateChan UNUSED)
{
	int FirstItem = currentPage*4;
	for(int i = FirstItem; i < (int) mainButton.size() && i < FirstItem+4; ++i)
	{
		if(sender == mainButton[i])
		{
			if(state == STATE_DEFAULT)
				mainButtonTxt[i]->SetPosition(0, 10);
			else
				mainButtonTxt[i]->SetPosition(0, 3);
			
			break;
		}
	}
}

void ThemeLoader::OnMainButtonClick(GuiButton *sender, int pointer UNUSED, const POINT &p UNUSED)
{
	//FlyingButtonsMenu::OnMainButtonClick(sender, pointer, p);
	
	for(u32 i = 0; i < mainButton.size(); ++i)
	{
		if(sender != mainButton[i])
			continue;
		
		ThemeInfosWindow * Infos = new ThemeInfosWindow(ThemeList[i].Title.c_str(),
														ThemeList[i].Team.c_str(),
														ThemeList[i].Version.c_str(),
														ThemeInfosWindow::LOAD);
		
		int choice = -1;
		while((choice = Infos->GetChoice()) < 0)
			Application::Instance()->updateEvents();
		
		Infos->SetEffect(EFFECT_SLIDE_TOP | EFFECT_SLIDE_OUT, 50);
		while(Infos->IsAnimated())
			Application::Instance()->updateEvents();
		
		Application::Instance()->PushForDelete(Infos);
		Application::Instance()->updateEvents();
		
		if(choice)
		{
			if(WindowPrompt(tr( "Do you want to load this theme?" ), ThemeList[i].Title.c_str(), tr( "Yes" ), tr( "Cancel" )))
			{
				Application::Instance()->setReload(Application::RELOAD_THEME);
				
				if (Theme::Load(ThemeList[i].Filepath.c_str()))
				{
					snprintf(Settings.Theme, sizeof(Settings.Theme), ThemeList[i].Filepath.c_str());
					Settings.Save();
				}
				else
					Theme::Load(Settings.Theme);
				
				ThemeReloadRequest();
			}
		}
		
		break;
	}
}
